/*
 * @Descripttion:
 * @Author: jhw
 * @Date: 2023-04-12 09:49:20
 * @LastEditors: jhw
 * @LastEditTime: 2023-05-19 22:51:49
 */
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios';
import { ElLoading } from 'element-plus';
import { LoadingInstance } from 'element-plus/es/components/loading/src/loading';

// 自定义请求返回数据的类型
interface Result<T> {
  msg?: string;
  code: number;
  data: T;
  t: number;
}

interface InterceptorHooks {
  requestInterceptor?: (config: AxiosRequestConfig) => any;
  responseInterceptors?: (res: AxiosResponse) => any;
  requestInterceptorsCatch?: (error: AxiosError) => void;
  responseInterceptorsCatch?: (error: AxiosError) => void;
}

interface HRequestConfig extends AxiosRequestConfig {
  interceptorHooks?: InterceptorHooks;
  showLoading?: boolean;
  withToken?: boolean;
  isReturnNativeResponse?: boolean;
}

interface HResConfig extends AxiosResponse {
  withToken?: boolean;
}

class HRequest {
  config: HRequestConfig;
  interceptorHooks?: InterceptorHooks;
  showLoading?: boolean;
  loading?: LoadingInstance;
  instance: AxiosInstance;

  constructor(options: HRequestConfig) {
    this.config = options;
    this.instance = axios.create(options);
    this.setupInterceptor();
  }

  // 类型参数的作用，T决定AxiosResponse实例中data的类型
  request<T = any>(config: HRequestConfig): Promise<T> {
    return new Promise((resolve, reject) => {
      this.instance
        .request<any, Result<T>>(config)
        .then((res) => {
          resolve(res.data);
        })
        .catch((err) => {
          reject(err);
        });
    });
  }

  setupInterceptor(): void {
    this.instance.interceptors.request.use(
      this.config.interceptorHooks?.requestInterceptor,
      this.config.interceptorHooks?.requestInterceptorsCatch,
    );
    this.instance.interceptors.response.use(
      this.config.interceptorHooks?.responseInterceptors,
      this.config.interceptorHooks?.responseInterceptorsCatch,
    );

    this.instance.interceptors.request.use((config) => {
      //设置loading
      if (this.showLoading) {
        this.loading = ElLoading.service({
          lock: true,
          text: 'Loading',
          spinner: 'el-icon-loading',
          background: 'rgba(0, 0, 0, 0.7)',
        });
      }
      return config;
    });

    this.instance.interceptors.response.use(
      // 请求完毕，关闭loading
      (res) => {
        this.loading?.close();
        return res;
      },
      (err) => {
        this.loading?.close();
        return err;
      },
    );
  }

  get<T = any>(config: HRequestConfig): Promise<T> {
    return this.request({ ...config, method: 'GET' });
  }

  post<T = any>(config: HRequestConfig): Promise<T> {
    return this.request({ ...config, method: 'POST' });
  }

  delete<T = any>(config: HRequestConfig): Promise<T> {
    return this.request({ ...config, method: 'DELETE' });
  }

  patch<T = any>(config: HRequestConfig): Promise<T> {
    return this.request({ ...config, method: 'PATCH' });
  }
}

export { HRequest, HRequestConfig, InterceptorHooks, HResConfig };
